package cn.crex1.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

public class Server1 {

    private Integer port;

    private ServerBootstrap server;

    private EventLoopGroup receiveGroup;

    private EventLoopGroup workGruop;

    private ServerHandler serverHanler;

    private ChannelFuture channelFuture;

    public Server1() {
        this.port = 8881;
        init();
    }

    public Server1(Integer port) {
        this.port = port;
        init();

    }

    private void init() {
        this.server = new ServerBootstrap();
        this.receiveGroup = new NioEventLoopGroup();
        this.workGruop = new NioEventLoopGroup();
        this.serverHanler = new ServerHandler();
        server.group(receiveGroup, workGruop)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
//                        ch.pipeline().addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                        ch.pipeline().addLast(new LineBasedFrameDecoder(2048));//字节解码器 ,其中2048是规定一行数据最大的字节数。  用于解决拆包问题
                        ch.pipeline().addLast(new FixedLengthFrameDecoder(100));//定长数据帧的解码器 ，每帧数据100个字节就切分一次。  用于解决粘包问题
                        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));
                        ch.pipeline().addLast("strEncoder", new StringEncoder());
                        ch.pipeline().addLast("strDecoder", new StringDecoder());
                        ch.pipeline().addLast(serverHanler);
                    }
                })
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

    }

    public void start() {
        try {
            channelFuture = server.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            receiveGroup.shutdownGracefully();
            workGruop.shutdownGracefully();
            e.printStackTrace();
        }
    }

    @ChannelHandler.Sharable
    private class ServerHandler extends ChannelInboundHandlerAdapter {

        private Boolean flag = false;

        private static final String CLOSECHANNEL_SEQUENCE="close_channel";

        /**
         * 空闲次数
         */
        private Integer idleCount = 0;
        /**
         * 心跳检测
         * @param ctx
         * @param evt
         * @throws Exception
         */
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent) {
                IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
                if (IdleState.READER_IDLE.equals(idleStateEvent.state())) {
                    System.out.println("已经10秒没有收到客户端的心跳连接了！");
                    if (idleCount > 2) {
                        System.out.println("关闭这个不活跃Channel");
                        ctx.writeAndFlush(CLOSECHANNEL_SEQUENCE);
                        ctx.channel().close();
                    }
                    idleCount++;
                }
            } else {
                super.userEventTriggered(ctx, evt);
            }
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof String) {
                String message = (String) msg;
                if ("hb_request".equals(message)) { //如果是心跳命令
                    System.out.println("服务端成功收到心跳信息");
                    ctx.write("服务端成功收到心跳信息");
                    ctx.flush();
                }
            } else {
                ByteBuf byteBuf = (ByteBuf) msg;
                String reqest = new String(byteBuf.array(), "UTF-8");
                System.out.println(reqest);
            }
            ctx.writeAndFlush("来自服务端的应答\n" + msg);
            flag = true;
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            System.out.println("信息读取完成");
            super.channelReadComplete(ctx);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }

        public Boolean getFlag() {
            return flag;
        }
    }
}
